package com.szgz.platform.service.impl;


import com.szgz.platform.constants.DockerConstant;
import com.szgz.platform.enums.EnvTypeEnum;
import com.szgz.platform.model.TeacherEnvironment;
import com.szgz.platform.model.UserEnvironment;
import com.szgz.platform.request.ResourceEnvironmentRequest;
import com.szgz.platform.result.ApiResponse;
import com.szgz.platform.result.ResourceEnvironmentResult;
import com.szgz.platform.service.ResourceEnvironmentService;
import com.szgz.platform.service.TeacherEnvironmentService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class ResourceEnvironmentServiceImpl implements ResourceEnvironmentService {


    @Resource
    private TeacherEnvironmentService teacherEnvironmentService;


    @Override
    public List<ResourceEnvironmentResult> createResourceEnvironment(ResourceEnvironmentRequest request) {

        List<ResourceEnvironmentResult> resourceEnvironmentResults = new ArrayList<>();

        for (String environmentType : request.getEnvironmentTypes()) {
            ResourceEnvironmentResult environment = new ResourceEnvironmentResult();
            log.info("环境类型: {}", environmentType);
            TeacherEnvironment teacherEnvironment = teacherEnvironmentService.create(new TeacherEnvironment().setType(environmentType).setName(environmentType));
            environment.setEnvironmentType(environmentType);
            environment.setResourceEnvironmentId(teacherEnvironment.getEnvironmentId());
            environment.setResourceType(EnvTypeEnum.getByType(environmentType).getType());
            environment.setContainerName(teacherEnvironment.getContainerName());
            environment.setAccessAddress(teacherEnvironment.getBaseUrl());
            environment.setPort(teacherEnvironment.getPortMapping());
            environment.setDescription(request.getDescription());
            environment.setMachineCount(request.getMachineCount());
            environment.setCpu(request.getCpu());
            environment.setMemory(request.getMemory());
            environment.setDisk(request.getDisk());
            environment.setGpu(request.getGpu());
            environment.setSystemEnvironment(request.getSystemEnvironment());
            environment.setUsername("root");
            environment.setPassword("123456");

            resourceEnvironmentResults.add(environment);
        }

        return resourceEnvironmentResults;
    }

    @Override
    public ApiResponse<String> deleteResourceEnvironment(String environmentId) {
        boolean deleteEnvironment = teacherEnvironmentService.deleteEnvironment(environmentId);
        if (!deleteEnvironment) {
            return ApiResponse.fail("删除失败");
        }
        return ApiResponse.success("删除成功");
    }

    @Override
    public ResourceEnvironmentResult getResourceEnvironmentStatus(String requestId) {
        return null;
    }


    public static void main(String[] args) {
        String replace = UUID.randomUUID().toString().replace("-", "");
        System.out.println(replace);
    }


//    private void createSharedMySQLEnvironment(ResourceEnvironmentResult environment) {
//        String groupId = UUID.randomUUID().toString();
//        try {
//            String groupDir = SHARED_DIR + "/" + groupId + "-mysql";
//            java.nio.file.Files.createDirectories(java.nio.file.Paths.get(groupDir));
//
//            // 统一使用一个对外端口
//            int mysqlPort = sharedContainerService.allocatePort();
//
//            // 生成 docker-compose.yml
//            String compose = new StringBuilder()
//                    .append("services:\n")
//                    .append("  mysql-shared-").append(groupId).append(":\n")
//                    .append("    image: mysql:5.7\n")
//                    .append("    container_name: mysql-shared-").append(groupId).append("\n")
//                    .append("    ports:\n")
//                    .append("      - \"").append(mysqlPort).append(":3306\"\n")
//                    .append("    environment:\n")
//                    .append("      MYSQL_ROOT_PASSWORD: 123456\n")
//                    .append("    volumes:\n")
//                    .append("      - shared-").append(groupId).append("-mysql-data:/var/lib/mysql\n")
//                    .append("    command: --default-authentication-plugin=mysql_native_password\n")
//                    .append("    restart: unless-stopped\n")
//                    .append("    networks:\n")
//                    .append("      - shared-").append(groupId).append("-mysql-net\n\n")
//                    .append("volumes:\n")
//                    .append("  shared-").append(groupId).append("-mysql-data:\n")
//                    .append("    driver: local\n\n")
//                    .append("networks:\n")
//                    .append("  shared-").append(groupId).append("-mysql-net:\n")
//                    .append("    driver: bridge\n")
//                    .toString();
//
//            java.nio.file.Files.write(java.nio.file.Paths.get(groupDir, "docker-compose.yml"), compose.getBytes());
//
//            // 启动容器
//            ProcessBuilder up = sharedContainerService.pbDocker("compose", "up", "-d");
//            up.directory(new java.io.File(groupDir));
//            Process upProc = up.start();
//            upProc.waitFor();
//
//            String containerName = MYSQL_SHARED_PREFIX + groupId;
//            environment.setContainerName(containerName);
//
//
//        } catch (Exception e) {
//            log.error("创建共享MySQL资源环境失败 failed", e);
//            throw new BusinessException("创建共享MySQL资源环境失败 failed: " + e.getMessage());
//        }
//    }


//    private void createMysqlSharedEnvStudentAccounts(String containerName, TeacherEnvironmentUsage usage) {
//
//        String mysqlUser = ("u" + usage.getStudentNo());
//        usage.setDbUsername(mysqlUser);
//        String dbName = mysqlUser + "_db";
//        usage.setDbName(dbName);
//        String password = "p" + usage.getStudentNo(); // 可后续改为按需生成
//        usage.setDbPassword(password);
//
//        String sql = "mysql -uroot -p123456 -e \""
//                + "CREATE USER IF NOT EXISTS '" + mysqlUser + "'@'%' IDENTIFIED BY '" + password + "'; "
//                + "CREATE DATABASE IF NOT EXISTS " + dbName + " DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; "
//                + "ALTER DATABASE " + dbName + " CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; "
//                + "GRANT ALL PRIVILEGES ON " + dbName + ".* TO '" + mysqlUser + "'@'%'; "
//                + "FLUSH PRIVILEGES;"
//                + "\"";
//
//        try {
//            ProcessBuilder exec = sharedContainerService.pbDocker("exec", containerName, "sh", "-lc", sql);
//            Process ep = exec.start();
//            int exit = ep.waitFor();
//            if (exit != 0) {
//                String err = new String(ep.getErrorStream().readAllBytes());
//                throw new RuntimeException("配置 MySQL 用户失败： " + usage.getStudentNo() + ": " + err);
//            }
//        } catch (IOException | InterruptedException e) {
//            throw new RuntimeException(e);
//        }
//
//    }


    private void createDockerEnvironment(String userId, Map<String, Integer> ports, Set<UserEnvironment.EnvironmentType> environmentTypes) throws Exception {
        log.info("createDockerEnvironment开始执行，用户: {}, 端口: {}, 类型: {}", userId, ports, environmentTypes);
        String userDir = DockerConstant.USERS_DIR + "/" + userId;
        Files.createDirectories(Paths.get(userDir));

        // 预拉取需要的镜像，特别是虚拟桌面镜像
        prePullRequiredImages(environmentTypes);

        String dockerComposeContent = generateDockerCompose(userId, ports, environmentTypes);
        Files.write(Paths.get(userDir + "/docker-compose.yml"), dockerComposeContent.getBytes());

        // 使用重试逻辑执行docker compose up
        executeDockerComposeWithRetry(userDir, userId);

        // 等待容器启动
        Thread.sleep(5000);

        // 验证所有需要的服务是否已启动（例如 MYSQL/REDIS/等）
        if (!verifyServicesRunning(userId, ports)) {
            log.error("Service verification failed after compose up for user {}.", userId);
            throw new RuntimeException("Some services are not running after compose up. See logs for details.");
        }

        // 修复权限问题（仅对IDE/Jupyter有效，其他服务忽略失败）
        fixContainerPermissions(userId);

        log.info("createDockerEnvironment执行完成，用户: {}", userId);
    }


    private void prePullRequiredImages(Set<UserEnvironment.EnvironmentType> environmentTypes) {
        try {
            if (environmentTypes.contains(UserEnvironment.EnvironmentType.VIRTUAL_DESKTOP)) {
                log.info("Pre-pulling virtual desktop image...");
                ProcessBuilder pb = new ProcessBuilder("/usr/bin/docker", "pull", "accetto/ubuntu-vnc-xfce-firefox-g3:latest");
                pb.redirectErrorStream(true);
                Process process = pb.start();

                StringBuilder output = new StringBuilder();
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        output.append(line).append("\n");
                    }
                }

                int exitCode = process.waitFor();
                if (exitCode != 0) {
                    log.warn("Failed to pre-pull virtual desktop image: {}", output.toString());
                    // 不抛出异常，让docker compose尝试拉取
                } else {
                    log.info("Successfully pre-pulled virtual desktop image");
                }
            }
        } catch (Exception e) {
            log.warn("Error during image pre-pull: {}", e.getMessage());
            // 不抛出异常，让docker compose尝试拉取
        }
    }


    private String generateDockerCompose(String userId, Map<String, Integer> ports, Set<UserEnvironment.EnvironmentType> environmentTypes) {
        StringBuilder compose = new StringBuilder();
        compose.append("services:\n");

        log.info("创建环境走的：ResourceEnvironmentServiceImpl");
        // IDE服务
        if (environmentTypes.contains(UserEnvironment.EnvironmentType.IDE)) {
            compose.append("  ide-").append(userId).append(":\n");
            compose.append("    image: crpi-ycy45s92ut53ifd4.cn-hangzhou.personal.cr.aliyuncs.com/boogie0095/code-server-rebuild:latest\n");
            compose.append("    container_name: ide-").append(userId).append("\n");
            compose.append("    ports:\n");
            compose.append("      - \"").append(ports.get("ide")).append(":8080\"\n");
            compose.append("    environment:\n");
            compose.append("      # 强制禁用密码认证，实现无密码登录\n");
            compose.append("      PASSWORD: \"\"\n");
            compose.append("      AUTH: none\n");
            compose.append("      # 禁用认证相关配置\n");
            compose.append("      DISABLE_AUTH: true\n");
            compose.append("      SKIP_AUTH: true\n");
            compose.append("      # code-server 无密码启动参数\n");
            compose.append("      CS_AUTH: none\n");
            compose.append("      CS_DISABLE_AUTH: true\n");
            compose.append("      # 覆盖镜像默认配置\n");
            compose.append("      DEFAULT_PASSWORD: \"\"\n");
            compose.append("      FORCE_NO_AUTH: true\n");
            compose.append("      USER_ID: ").append(userId).append("\n");
            compose.append("      # 剪贴板权限配置\n");
            compose.append("      ENABLE_CLIPBOARD: true\n");
            compose.append("      CLIPBOARD_READ: true\n");
            compose.append("      CLIPBOARD_WRITE: true\n");
            compose.append("      # 浏览器权限配置\n");
            compose.append("      BROWSER_PERMISSIONS: clipboard-read,clipboard-write\n");
            compose.append("      # 安全配置\n");
            compose.append("      SECURITY_ALLOW_INSECURE_LOCALHOST: true\n");
            compose.append("      SECURITY_ALLOW_HTTP: true\n");
            compose.append("      # 额外权限配置\n");
            compose.append("      EXTENSIONS_GALLERY: '{\"serviceUrl\":\"https://marketplace.visualstudio.com/_apis/public/gallery\",\"cacheUrl\":\"https://vscode.cdn.azure.cn\",\"itemUrl\":\"https://marketplace.visualstudio.com/items\"}'\n");
            compose.append("    # 强制覆盖启动命令，确保无密码启动\n");
            compose.append("    command: [\"/usr/bin/entrypoint.sh\", \"code-server\", \"--bind-addr\", \"0.0.0.0:8080\", \"--auth\", \"none\", \"/home/coder/project\"]\n");
            compose.append("    volumes:\n");
            compose.append("      - user-").append(userId).append("-data:/home/coder/project\n");
            compose.append("      - user-").append(userId).append("-config:/home/coder/.config\n");
            compose.append("    deploy:\n");
            compose.append("      resources:\n");
            compose.append("        limits:\n");
            compose.append("          cpus: '2'\n");
            compose.append("          memory: 4G\n");
            compose.append("        reservations:\n");
            compose.append("          cpus: '0.5'\n");
            compose.append("          memory: 1G\n");
            compose.append("    restart: unless-stopped\n");
            compose.append("    networks:\n");
            compose.append("      - user-").append(userId).append("-network\n\n");
        }

        // Jupyter服务
        if (environmentTypes.contains(UserEnvironment.EnvironmentType.JUPYTER)) {
            compose.append("  jupyter-").append(userId).append(":\n");
//            compose.append("    image: jupyter/datascience-notebook:latest\n");
            compose.append("    image: jupyter/minimal-notebook:latest\n");
            compose.append("    container_name: jupyter-").append(userId).append("\n");
            compose.append("    ports:\n");
            compose.append("      - \"").append(ports.get("jupyter")).append(":8888\"\n");
            compose.append("    environment:\n");
            compose.append("      JUPYTER_ENABLE_LAB: yes\n");
            compose.append("      # 禁用Jupyter认证，实现无密码登录\n");
            compose.append("      JUPYTER_TOKEN: \"\"\n");
            compose.append("      JUPYTER_PASSWORD: \"\"\n");
            compose.append("      # 禁用密码和token认证\n");
            compose.append("      JUPYTER_DISABLE_AUTH: true\n");
            compose.append("      # 禁用安全模式\n");
            compose.append("      JUPYTER_ALLOW_INSECURE_WRITES: true\n");
            compose.append("    # 强制覆盖启动命令，确保无密码启动\n");
            compose.append("    command: [\"start-notebook.sh\", \"--NotebookApp.token=''\", \"--NotebookApp.password=''\", \"--NotebookApp.disable_check_xsrf=True\", \"--NotebookApp.allow_origin='*'\"]\n");
            compose.append("    volumes:\n");
            compose.append("      - user-").append(userId).append("-data:/home/jovyan/work\n");
            compose.append("    deploy:\n");
            compose.append("      resources:\n");
            compose.append("        limits:\n");
            compose.append("          cpus: '2'\n");
            compose.append("          memory: 4G\n");
            compose.append("        reservations:\n");
            compose.append("          cpus: '0.5'\n");
            compose.append("          memory: 1G\n");
            compose.append("    networks:\n");
            compose.append("      - user-").append(userId).append("-network\n\n");
        }

        // 轻量级Jupyter服务
        if (environmentTypes.contains(UserEnvironment.EnvironmentType.JUPYTER_LIGHT)) {
            compose.append("  jupyter-light-").append(userId).append(":\n");
            compose.append("    image: jupyter/minimal-notebook:latest\n");
            compose.append("    container_name: jupyter-light-").append(userId).append("\n");
            compose.append("    ports:\n");
            compose.append("      - \"").append(ports.get("jupyter")).append(":8888\"\n");
            compose.append("    environment:\n");
            compose.append("      JUPYTER_ENABLE_LAB: yes\n");
            compose.append("      # 禁用Jupyter认证，实现无密码登录\n");
            compose.append("      JUPYTER_TOKEN: \"\"\n");
            compose.append("      JUPYTER_PASSWORD: \"\"\n");
            compose.append("      # 禁用密码和token认证\n");
            compose.append("      JUPYTER_DISABLE_AUTH: true\n");
            compose.append("      # 轻量级配置\n");
            compose.append("      JUPYTER_CONFIG_DIR: /home/jovyan/.jupyter\n");
            compose.append("      # 禁用不必要的扩展和功能\n");
            compose.append("      JUPYTER_DISABLE_EXTENSIONS: yes\n");
            compose.append("      # 设置工作目录\n");
            compose.append("      WORK_DIR: /home/jovyan/work\n");
            compose.append("      # 内存优化\n");
            compose.append("      JUPYTER_MEMORY_LIMIT: 1G\n");
            compose.append("      # 禁用自动保存以减少磁盘I/O\n");
            compose.append("      JUPYTER_AUTOSAVE_INTERVAL: 0\n");
            compose.append("      # 禁用安全模式\n");
            compose.append("      JUPYTER_ALLOW_INSECURE_WRITES: true\n");
            compose.append("    # 强制覆盖启动命令，确保无密码启动\n");
            compose.append("    command: [\"start-notebook.sh\", \"--NotebookApp.token=''\", \"--NotebookApp.password=''\", \"--NotebookApp.disable_check_xsrf=True\", \"--NotebookApp.allow_origin='*'\"]\n");
            compose.append("    volumes:\n");
            compose.append("      - user-").append(userId).append("-data:/home/jovyan/work\n");
            compose.append("    deploy:\n");
            compose.append("      resources:\n");
            compose.append("        limits:\n");
            compose.append("          cpus: '1'\n");
            compose.append("          memory: 2G\n");
            compose.append("        reservations:\n");
            compose.append("          cpus: '0.25'\n");
            compose.append("          memory: 512M\n");
            compose.append("    networks:\n");
            compose.append("      - user-").append(userId).append("-network\n\n");
        }

        // 虚拟桌面服务
                   if (environmentTypes.contains(UserEnvironment.EnvironmentType.VIRTUAL_DESKTOP)) {
               compose.append("  virtual-desktop-").append(userId).append(":\n");
               compose.append("    image: dorowu/ubuntu-desktop-lxde-vnc:latest\n");
               compose.append("    container_name: virtual-desktop-").append(userId).append("\n");
               compose.append("    ports:\n");
               compose.append("      - \"").append(ports.get("virtual-desktop")).append(":80\"\n");
               compose.append("    environment:\n");
               compose.append("      # 设置VNC密码\n");
               compose.append("      VNC_PW: \"123456\"\n");
               compose.append("      VNC_PASSWORD: \"123456\"\n");
               compose.append("      VNC_NO_PASSWORD: \"0\"\n");
               compose.append("      VNC_DISABLE_AUTH: \"0\"\n");
               compose.append("      # 显示配置\n");
               compose.append("      RESOLUTION: 1920x1080\n");
               compose.append("      # 用户配置\n");
               compose.append("      USER: 1000\n");
               compose.append("      # 语言配置\n");
               compose.append("      LANG: zh_CN.UTF-8\n");
               compose.append("      LC_ALL: zh_CN.UTF-8\n");
               compose.append("      LANGUAGE: zh_CN:zh\n");
               compose.append("      TZ: Asia/Shanghai\n");
                                       compose.append("    command: [\"/dockerstartup/vnc_startup.rc\"]\n");
               compose.append("    volumes:\n");
               compose.append("      - user-").append(userId).append("-desktop-data:/home/accetto/Desktop\n");
               compose.append("      - user-").append(userId).append("-data:/home/accetto/shared\n");
               compose.append("    deploy:\n");
               compose.append("      resources:\n");
               compose.append("        limits:\n");
               compose.append("          cpus: '1'\n");
               compose.append("          memory: 2G\n");
               compose.append("        reservations:\n");
               compose.append("          cpus: '0.25'\n");
               compose.append("          memory: 512M\n");
               compose.append("    restart: unless-stopped\n");
               compose.append("    networks:\n");
               compose.append("      - user-").append(userId).append("-network\n\n");
           }

        // 检查是否需要创建多服务容器（MySQL + Redis）
        boolean needMysql = environmentTypes.contains(UserEnvironment.EnvironmentType.MYSQL);
        boolean needRedis = environmentTypes.contains(UserEnvironment.EnvironmentType.REDIS);

        if (needMysql && needRedis) {
            // 创建多服务容器（MySQL + Redis）
            createMultiServiceContainer(compose, userId, ports);
        } else {
            // 单独创建Redis服务
            if (needRedis) {
                compose.append("  redis-").append(userId).append(":\n");
                compose.append("    image: redis:7-alpine\n");
                compose.append("    container_name: redis-").append(userId).append("\n");
                compose.append("    ports:\n");
                compose.append("      - \"").append(ports.get("redis")).append(":6379\"\n");
                compose.append("    command: redis-server --requirepass 123456\n");
                compose.append("    volumes:\n");
                compose.append("      - user-").append(userId).append("-redis-data:/data\n");
                compose.append("    deploy:\n");
                compose.append("      resources:\n");
                compose.append("        limits:\n");
                compose.append("          cpus: '1'\n");
                compose.append("          memory: 1G\n");
                compose.append("        reservations:\n");
                compose.append("          cpus: '0.2'\n");
                compose.append("          memory: 256M\n");
                compose.append("    networks:\n");
                compose.append("      - user-").append(userId).append("-network\n\n");
            }

            // 单独创建MySQL服务
            if (needMysql) {
                createMysqlService(compose, userId, ports);
            }
        }

        // RabbitMQ服务
        if (environmentTypes.contains(UserEnvironment.EnvironmentType.RABBITMQ)) {
            compose.append("  rabbitmq-").append(userId).append(":\n");
            compose.append("    image: rabbitmq:3-management\n");
            compose.append("    container_name: rabbitmq-").append(userId).append("\n");
            compose.append("    ports:\n");
            compose.append("      - \"").append(ports.get("rabbitmq")).append(":5672\"\n");
            compose.append("      - \"").append(ports.get("rabbitmq") + 1).append(":15672\"\n");
            compose.append("    environment:\n");
            compose.append("      RABBITMQ_DEFAULT_USER: user_").append(userId).append("\n");
            compose.append("      RABBITMQ_DEFAULT_PASS: 123456\n");
            compose.append("    volumes:\n");
            compose.append("      - user-").append(userId).append("-rabbitmq-data:/var/lib/rabbitmq\n");
            compose.append("    deploy:\n");
            compose.append("      resources:\n");
            compose.append("        limits:\n");
            compose.append("          cpus: '1'\n");
            compose.append("          memory: 1G\n");
            compose.append("        reservations:\n");
            compose.append("          cpus: '0.2'\n");
            compose.append("          memory: 256M\n");
            compose.append("    networks:\n");
            compose.append("      - user-").append(userId).append("-network\n\n");
        }

        // Elasticsearch服务
        if (environmentTypes.contains(UserEnvironment.EnvironmentType.ELASTICSEARCH)) {
            compose.append("  elasticsearch-").append(userId).append(":\n");
            compose.append("    image: elasticsearch:8.11.0\n");
            compose.append("    container_name: elasticsearch-").append(userId).append("\n");
            compose.append("    ports:\n");
            compose.append("      - \"").append(ports.get("elasticsearch")).append(":9200\"\n");
            compose.append("      - \"").append(ports.get("elasticsearch") + 1).append(":9300\"\n");
            compose.append("    environment:\n");
            compose.append("      - discovery.type=single-node\n");
            compose.append("      - xpack.security.enabled=false\n");
            compose.append("      - \"ES_JAVA_OPTS=-Xms512m -Xmx512m\"\n");
            compose.append("    volumes:\n");
            compose.append("      - user-").append(userId).append("-elasticsearch-data:/usr/share/elasticsearch/data\n");
            compose.append("    deploy:\n");
            compose.append("      resources:\n");
            compose.append("        limits:\n");
            compose.append("          cpus: '1'\n");
            compose.append("          memory: 2G\n");
            compose.append("        reservations:\n");
            compose.append("          cpus: '0.2'\n");
            compose.append("          memory: 512M\n");
            compose.append("    networks:\n");
            compose.append("      - user-").append(userId).append("-network\n\n");
        }

        // Volumes
        compose.append("volumes:\n");
        compose.append("  user-").append(userId).append("-data:\n");
        compose.append("    driver: local\n");

        // 添加 IDE 配置卷定义
        if (environmentTypes.contains(UserEnvironment.EnvironmentType.IDE)) {
            compose.append("  user-").append(userId).append("-config:\n");
            compose.append("    driver: local\n");
        }

        if (environmentTypes.contains(UserEnvironment.EnvironmentType.VIRTUAL_DESKTOP)) {
            compose.append("  user-").append(userId).append("-desktop-data:\n");
            compose.append("    driver: local\n");
        }

        if (environmentTypes.contains(UserEnvironment.EnvironmentType.REDIS)) {
            compose.append("  user-").append(userId).append("-redis-data:\n");
            compose.append("    driver: local\n");
        }

        if (environmentTypes.contains(UserEnvironment.EnvironmentType.MYSQL)) {
            compose.append("  user-").append(userId).append("-mysql-data:\n");
            compose.append("    driver: local\n");
        }

        if (environmentTypes.contains(UserEnvironment.EnvironmentType.RABBITMQ)) {
            compose.append("  user-").append(userId).append("-rabbitmq-data:\n");
            compose.append("    driver: local\n");
        }

        if (environmentTypes.contains(UserEnvironment.EnvironmentType.ELASTICSEARCH)) {
            compose.append("  user-").append(userId).append("-elasticsearch-data:\n");
            compose.append("    driver: local\n");
        }

        // Networks
        compose.append("networks:\n");
        compose.append("  user-").append(userId).append("-network:\n");
        compose.append("    driver: bridge\n");

        return compose.toString();
    }


    private void executeDockerComposeWithRetry(String userDir, String userId) throws Exception {
        int maxRetries = 3;
        int retryCount = 0;
        Exception lastException = null;

        while (retryCount < maxRetries) {
            try {
                ProcessBuilder pb = new ProcessBuilder("/usr/bin/docker", "compose", "up", "-d");
                pb.directory(new File(userDir));
                pb.redirectErrorStream(true);
                Process process = pb.start();

                // 读取输出
                StringBuilder output = new StringBuilder();
                boolean processCompleted = false;

                // 使用线程来读取输出，避免阻塞
                Thread outputReader = new Thread(() -> {
                    try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
                        String line;
                        while ((line = reader.readLine()) != null) {
                            output.append(line).append("\n");
                        }
                    } catch (IOException e) {
                        log.warn("Error reading process output: {}", e.getMessage());
                    }
                });
                outputReader.start();

                // 等待进程完成，设置超时时间（5分钟）
                boolean completed = process.waitFor(5, TimeUnit.MINUTES);
                if (!completed) {
                    log.warn("Docker compose up timeout for user {} (attempt {})", userId, retryCount + 1);
                    process.destroyForcibly();
                    lastException = new RuntimeException("Docker compose up timeout after 5 minutes");
                } else {
                    outputReader.join(10000); // 等待输出读取线程完成
                    processCompleted = true;

                    int exitCode = process.exitValue();
                    if (exitCode == 0) {
                        log.info("Docker compose up successful for user {} (attempt {})", userId, retryCount + 1);
                        return;
                    } else {
                        log.warn("Docker compose failed for user {} (attempt {}): {}", userId, retryCount + 1, output.toString());
                        lastException = new RuntimeException("Docker compose failed: " + output.toString());
                    }
                }
            } catch (Exception e) {
                log.warn("Exception during docker compose up for user {} (attempt {}): {}", userId, retryCount + 1, e.getMessage());
                lastException = e;
            }

            retryCount++;
            if (retryCount < maxRetries) {
                log.info("Retrying docker compose up for user {} (attempt {}/{})", userId, retryCount + 1, maxRetries);
                Thread.sleep(2000 * retryCount); // 递增延迟
            }
        }

        // 所有重试都失败了
        log.error("All {} attempts to run docker compose up failed for user {}", maxRetries, userId);
        throw lastException != null ? lastException : new RuntimeException("Failed to create Docker environment after " + maxRetries + " attempts");
    }


    /**
     * 验证根据端口表应存在的服务容器是否已运行且端口映射生效
     */
    private boolean verifyServicesRunning(String userId, Map<String, Integer> ports) {
        try {
            log.info("开始验证服务状态，用户: {}, 端口: {}", userId, ports);
            final int maxAttempts = 60; // 增加到120秒，给MySQL等数据库服务更多启动时间
            for (int attempt = 1; attempt <= maxAttempts; attempt++) {
                log.info("执行docker ps命令，尝试: {}/{}", attempt, maxAttempts);
                ProcessBuilder pb = new ProcessBuilder("/usr/bin/docker", "ps", "--format", "{{.Names}}\t{{.Ports}}\t{{.Status}}");
                Process process = pb.start();
                java.util.List<String> lines = new java.util.ArrayList<>();
                java.util.List<String> errorLines = new java.util.ArrayList<>();
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                     BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        lines.add(line);
                    }
                    while ((line = errorReader.readLine()) != null) {
                        errorLines.add(line);
                    }
                }
                process.waitFor();

                log.info("docker ps命令执行完成，退出码: {}, 输出行数: {}, 错误行数: {}", process.exitValue(), lines.size(), errorLines.size());
                if (!errorLines.isEmpty()) {
                    log.warn("docker ps命令错误输出:");
                    for (String errorLine : errorLines) {
                        log.warn("  {}", errorLine);
                    }
                }

                // 记录当前Docker容器状态，用于调试
                if (attempt == 1 || attempt % 10 == 0) {
                    log.info("当前Docker容器状态 (尝试 {}/{}):", attempt, maxAttempts);
                    for (String line : lines) {
                        log.info("  {}", line);
                    }
                }

                // 记录要查找的容器名称，用于调试
                log.info("正在查找的容器名称:");
                if (ports.containsKey("ide")) log.info("  IDE: ide-{}", userId);
                if (ports.containsKey("jupyter")) log.info("  Jupyter: jupyter-{}", userId);
                if (ports.containsKey("redis")) log.info("  Redis: redis-{}", userId);
                if (ports.containsKey("mysql")) log.info("  MySQL: mysql-{}", userId);
                if (ports.containsKey("rabbitmq")) log.info("  RabbitMQ: rabbitmq-{}", userId);
                if (ports.containsKey("elasticsearch")) log.info("  Elasticsearch: elasticsearch-{}", userId);
                if (ports.containsKey("virtual-desktop")) log.info("  虚拟桌面: virtual-desktop-{}", userId);

                boolean ok = true;
                if (ports.containsKey("ide") && lines.stream().noneMatch(l -> l.contains("ide-" + userId) && l.contains("Up"))) {
                    log.debug("IDE服务未就绪，尝试: {}/{}", attempt, maxAttempts);
                    ok = false;
                }
                if (ports.containsKey("jupyter") && lines.stream().noneMatch(l -> l.contains("jupyter-" + userId) && l.contains("Up"))) {
                    log.debug("Jupyter服务未就绪，尝试: {}/{}", attempt, maxAttempts);
                    ok = false;
                }
                if (ports.containsKey("redis") && lines.stream().noneMatch(l -> l.contains("redis-" + userId) && l.contains("Up"))) {
                    log.debug("Redis服务未就绪，尝试: {}/{}", attempt, maxAttempts);
                    ok = false;
                }
                if (ports.containsKey("mysql") && lines.stream().noneMatch(l -> l.contains("mysql-" + userId) && (l.contains("Up") || l.contains("starting") || l.contains("healthy") || l.contains("running")))) {
                    log.debug("MySQL服务未就绪，尝试: {}/{}", attempt, maxAttempts);
                    // 检查是否有MySQL容器存在，即使状态不是Up
                    boolean mysqlContainerExists = lines.stream().anyMatch(l -> l.contains("mysql-" + userId));
                    if (mysqlContainerExists) {
                        // 记录容器的实际状态
                        String containerStatus = lines.stream()
                                .filter(l -> l.contains("mysql-" + userId))
                                .findFirst()
                                .orElse("未找到状态信息");
                        log.info("MySQL容器存在但状态不正确，状态: {}, 尝试: {}/{}", containerStatus, attempt, maxAttempts);
                    } else {
                        log.info("MySQL容器不存在，尝试: {}/{}", attempt, maxAttempts);
                    }
                    ok = false;
                }
                if (ports.containsKey("rabbitmq") && lines.stream().noneMatch(l -> l.contains("rabbitmq-" + userId) && l.contains("Up"))) {
                    log.debug("RabbitMQ服务未就绪，尝试: {}/{}", attempt, maxAttempts);
                    ok = false;
                }
                if (ports.containsKey("elasticsearch") && lines.stream().noneMatch(l -> l.contains("elasticsearch-" + userId) && l.contains("Up"))) {
                    log.debug("Elasticsearch服务未就绪，尝试: {}/{}", attempt, maxAttempts);
                    ok = false;
                }
                if (ports.containsKey("virtual-desktop") && lines.stream().noneMatch(l -> l.contains("virtual-desktop-" + userId) && l.contains("Up"))) {
                    log.debug("虚拟桌面服务未就绪，尝试: {}/{}", attempt, maxAttempts);
                    ok = false;
                }

                if (ok) {
                    log.info("所有服务验证成功，用户: {}", userId);
                    return true;
                }

                // 每10次尝试记录一次日志
                if (attempt % 10 == 0) {
                    log.info("服务验证中，用户: {}, 尝试: {}/{}", userId, attempt, maxAttempts);
                }

                // 未全部就绪，等待后重试
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException ie) { /* ignore */ }
            }
            log.warn("服务验证超时，用户: {}, 等待了{}秒", userId, maxAttempts * 2);
            return false;
        } catch (Exception e) {
            log.error("Error verifying services for user {}: {}", userId, e.getMessage());
            return false;
        }
    }


    private void fixContainerPermissions(String userId) {
        try {
            log.info("Fixing permissions for user: {}", userId);

            // 检查并修复 IDE 容器权限（如果存在）
            if (containerExists("ide-" + userId)) {
                ProcessBuilder pb = new ProcessBuilder("/usr/bin/docker", "exec", "-u", "root", "ide-" + userId,
                        "chown", "-R", "coder:coder", "/home/coder/project");
                Process process = pb.start();
                int exitCode = process.waitFor();
                if (exitCode != 0) {
                    log.warn("IDE permission fix failed with exit code: {}", exitCode);
                } else {
                    log.info("IDE permissions fixed successfully");
                }

                // 设置目录权限为 755
                pb = new ProcessBuilder("/usr/bin/docker", "exec", "-u", "root", "ide-" + userId,
                        "chmod", "-R", "755", "/home/coder/project");
                process = pb.start();
                exitCode = process.waitFor();
                if (exitCode != 0) {
                    log.warn("IDE directory permissions fix failed with exit code: {}", exitCode);
                }
            }

            // 检查并修复 Jupyter 容器权限（如果存在）
            if (containerExists("jupyter-" + userId) || containerExists("jupyter-light-" + userId)) {
                String containerName = containerExists("jupyter-light-" + userId) ? "jupyter-light-" + userId : "jupyter-" + userId;
                ProcessBuilder pb = new ProcessBuilder("/usr/bin/docker", "exec", "-u", "root", containerName,
                        "chown", "-R", "jovyan:users", "/home/jovyan/work");
                Process process = pb.start();
                int exitCode = process.waitFor();
                if (exitCode != 0) {
                    log.warn("Jupyter permission fix failed with exit code: {}", exitCode);
                } else {
                    log.info("Jupyter permissions fixed successfully");
                }

                // 设置目录权限为 755
                pb = new ProcessBuilder("/usr/bin/docker", "exec", "-u", "root", containerName,
                        "chmod", "-R", "755", "/home/jovyan/work");
                process = pb.start();
                exitCode = process.waitFor();
                if (exitCode != 0) {
                    log.warn("Jupyter directory permissions fix failed with exit code: {}", exitCode);
                }
            }

            log.info("Permissions fixed for user: {}", userId);
        } catch (Exception e) {
            log.error("Failed to fix permissions for user: {}", userId, e);
        }
    }

    /**
     * 检查容器是否存在
     */
    private boolean containerExists(String containerName) {
        try {
            ProcessBuilder pb = new ProcessBuilder("/usr/bin/docker", "ps", "-a", "--format", "{{.Names}}");
            Process process = pb.start();
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    if (line.equals(containerName)) {
                        return true;
                    }
                }
            }
            process.waitFor();
        } catch (Exception e) {
            log.warn("Failed to check if container exists: {}", containerName, e);
        }
        return false;
    }

    private void createMultiServiceContainer(StringBuilder compose, String userId, Map<String, Integer> ports) {
        compose.append("  multi-service-").append(userId).append(":\n");
        compose.append("    image: redis:7-alpine\n"); // 使用一个基础镜像，例如 Redis
        compose.append("    container_name: multi-service-").append(userId).append("\n");
        compose.append("    ports:\n");
        compose.append("      - \"").append(ports.get("redis")).append(":6379\"\n"); // 映射 Redis 端口
        compose.append("    environment:\n");
        compose.append("      REDIS_PASSWORD: 123456\n"); // 设置 Redis 密码
        compose.append("    volumes:\n");
        compose.append("      - user-").append(userId).append("-redis-data:/data\n"); // 映射 Redis 数据卷
        compose.append("    deploy:\n");
        compose.append("      resources:\n");
        compose.append("        limits:\n");
        compose.append("          cpus: '1'\n");
        compose.append("          memory: 1G\n");
        compose.append("        reservations:\n");
        compose.append("          cpus: '0.2'\n");
        compose.append("          memory: 256M\n");
        compose.append("    networks:\n");
        compose.append("      - user-").append(userId).append("-network\n\n");

        // 创建 MySQL 服务
        compose.append("  mysql-").append(userId).append(":\n");
        compose.append("    image: mysql:5.7\n");
        compose.append("    container_name: mysql-").append(userId).append("\n");
        compose.append("    ports:\n");
        compose.append("      - \"").append(ports.get("mysql")).append(":3306\"\n"); // 映射 MySQL 端口
        compose.append("    environment:\n");
        compose.append("      MYSQL_ROOT_PASSWORD: 123456\n");
        compose.append("      MYSQL_DATABASE: u").append(userId).append("_db\n"); // 使用用户名作为数据库名
        compose.append("      MYSQL_USER: root\n");
        compose.append("      MYSQL_PASSWORD: 123456\n");
        compose.append("    volumes:\n");
        compose.append("      - user-").append(userId).append("-mysql-data:/var/lib/mysql\n"); // 映射 MySQL 数据卷
        compose.append("    deploy:\n");
        compose.append("      resources:\n");
        compose.append("        limits:\n");
        compose.append("          cpus: '1'\n");
        compose.append("          memory: 2G\n");
        compose.append("        reservations:\n");
        compose.append("          cpus: '0.2'\n");
        compose.append("          memory: 512M\n");
        compose.append("    command: --default-authentication-plugin=mysql_native_password\n");
        compose.append("    networks:\n");
        compose.append("      - user-").append(userId).append("-network\n\n");
    }

    private void createMysqlService(StringBuilder compose, String userId, Map<String, Integer> ports) {
        compose.append("  mysql-").append(userId).append(":\n");
        compose.append("    image: mysql:5.7\n");
        compose.append("    container_name: mysql-").append(userId).append("\n");
        compose.append("    ports:\n");
        compose.append("      - \"").append(ports.get("mysql")).append(":3306\"\n"); // 映射 MySQL 端口
        compose.append("    environment:\n");
        compose.append("      MYSQL_ROOT_PASSWORD: 123456\n");
        compose.append("      MYSQL_DATABASE: u").append(userId).append("_db\n"); // 使用用户名作为数据库名
        compose.append("      MYSQL_USER: root\n");
        compose.append("      MYSQL_PASSWORD: 123456\n");
        compose.append("    volumes:\n");
        compose.append("      - user-").append(userId).append("-mysql-data:/var/lib/mysql\n"); // 映射 MySQL 数据卷
        compose.append("    deploy:\n");
        compose.append("      resources:\n");
        compose.append("        limits:\n");
        compose.append("          cpus: '1'\n");
        compose.append("          memory: 2G\n");
        compose.append("        reservations:\n");
        compose.append("          cpus: '0.2'\n");
        compose.append("          memory: 512M\n");
        compose.append("    command: --default-authentication-plugin=mysql_native_password\n");
        compose.append("    networks:\n");
        compose.append("      - user-").append(userId).append("-network\n\n");
    }
}
